package org.eclipse.gittab.fretboard;

import org.eclipse.swt.widgets.Composite;

/**
 * Interface for drawing and handling a guitar fretboard. Various configuration
 * parameters can be set through {@link #setConfiguration(Configuration)}.
 * 
 * @author mat
 * 
 */
public interface Fretboard {

	/**
	 * Listener for actions performed on the {@link Fretboard}.
	 * 
	 * @author mat
	 * 
	 */
	public interface FretboardListener {

		/**
		 * A string on a fret has been clicked.
		 * 
		 * @param fret
		 *            <code>0</code> if open string
		 * @param string
		 *            starting from <code>1</code> is the lowest string
		 */
		public void clickedOn(int fret, int string);
	}

	/**
	 * Configures a {@link Fretboard}. Valid configurations can be checked with
	 * {@link #isValid()}.
	 * 
	 * @author mtreitle
	 * 
	 */
	public class Configuration {

		public static final int MAX_FRETS = 24;
		public static final int MIN_FRETS = 5;

		public static final int MAX_STRINGS = 7;
		public static final int MIN_STRINGS = 4;

		private Composite composite;
		private String[][] notes;
		private boolean lefty;

		public Composite getComposite() {
			return composite;
		}

		/**
		 * Sets the composite where the {@link Fretboard} will be painted.
		 * 
		 * @param parent
		 */
		public void setComposite(Composite composite) {
			this.composite = composite;
		}

		public String[][] getNotes() {
			return notes;
		}

		public int getStringsNr() {
			if (notes != null)
				return notes.length;
			return 0;
		}

		public int getFretsNr() {
			if (notes != null && notes[0] != null)
				return notes[0].length - 1;
			return 0;
		}

		/**
		 * Set the notes matrix.
		 * <p>
		 * The first dimension is the string (starting with the lowest string)
		 * and the second dimension the fret number.
		 * </p>
		 * The number of strings is determined by the length of the array. The
		 * array should start with (index 0) the lowest string and end with the
		 * highest string. </p> The frets start from 0 to number of frets. The
		 * 0th fret is the open string.
		 * 
		 * @param notes
		 * @return
		 */
		public void setNotes(String[][] notes) {
			this.notes = notes;
		}

		public void setLefty(boolean lefty) {
			this.lefty = lefty;
		}

		public boolean isLefty() {
			return lefty;
		}

		/**
		 * Checks if all parameters have been passed (except the design) and if
		 * the notes matrix is compatible with the number of strings and frets.
		 * </p> Minimal fret number is {@value #MIN_FRETS} and maximal fret
		 * number is {@value #MAX_FRETS}. </p> Minimal string number is
		 * {@value #MIN_STRINGS} and maximal string number is
		 * {@value #MAX_STRINGS}.
		 * 
		 * @return
		 */
		public boolean isValid() {

			return (isCompositeAvailable() && notes != null
					&& notes.length >= MIN_STRINGS
					&& notes.length <= MAX_STRINGS
					&& notes[0].length >= MIN_FRETS && notes[0].length <= MAX_FRETS);
		}

		public boolean isCompositeAvailable() {
			return composite != null;
		}
	}

	public void setConfiguration(Configuration configuration);

	public Configuration getConfiguration();

	/**
	 * Paints the fretboard according the current design. If no design is
	 * available the default design is used. </p> Call after
	 * {@link #setConfiguration(Configuration)}.
	 * 
	 */
	public void paint();

	// functional
	/**
	 * Marks a note on a string with the {@link FretboardDesign#playNote()}
	 * color. See also {@link #clear(int, int)} and {@link #clearAll()}.
	 * 
	 * @param fret
	 * @param string
	 */
	public void play(int fret, int string);

	/**
	 * Checks if the fret on the string is currently played.
	 * 
	 * @param fret
	 * @param string
	 * @return may return <code>true</code> although not played
	 */
	public boolean isPlaying(int fret, int string);

	/**
	 * Unmarks a note on a string. See also {@link #play(int, int)}.
	 * 
	 * @param fret
	 * @param string
	 */
	public void clear(int fret, int string);

	/**
	 * Unmarks all notes on every string. See also {@link #clear(int, int)}.
	 */
	public void clearAll();

	/**
	 * Sets the current design.
	 */
	public void setDesign(FretboardDesign design);

	/**
	 * Gets the current design.
	 * 
	 * @return the {@link #defaultDesign()} if no design has been set explicit.
	 */
	public FretboardDesign getCurrentDesign();

	/**
	 * Gets the default design provided by the implementation.
	 * 
	 * @return
	 */
	public FretboardDesign getDefaultDesign();

	// listener
	public void addFretboardListener(FretboardListener listener);

	public void removeFretboardListener(FretboardListener listener);
}
